﻿// ReSharper disable PossibleLossOfFraction
// ReSharper disable AccessToModifiedClosure
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Kernel;
using MindFusion.Diagramming.Layout;
using MindFusion.Diagramming.WinForms;
using ElectionAlgoritmForm.Diagramming;

using ElectionOfLeaderAlg.Controllers;
using ElectionOfLiderAlg;

namespace ElectionAlgoritmForm
{
    public partial class FormMain : Form
    {
        public const String StrRepeat = @"Повторить?";

        private static readonly Dictionary<GraphNode.NodeState, Color> StateColours = new Dictionary<GraphNode.NodeState, Color> 
        { 
            { GraphNode.NodeState.Active, Color.Green }, 
            { GraphNode.NodeState.Leader, Color.Red }, 
            { GraphNode.NodeState.Sleep, Color.Gray },
            { GraphNode.NodeState.Cand, Color.Blue },
            { GraphNode.NodeState.Lost, Color.DarkOrange },
            { GraphNode.NodeState.Passive, Color.Pink }
        };
        private ElectionRingLeLanController _LeLan;
        private ElectionRingChenRoberts _ChenRoberts;
        private ElectionRingPeterson _Peterson;
        private ElectionRingTree _Tree;
        private ElectionRingPhase _Phase;
        private int par1;
        private int par2;
        private int par3;
        private int par4;

        public FormMain()
        {
            InitializeComponent();
            MouseWheel += FormMainMouseWheel;
        }

        private static void BuildGraph(DiagramView diagramView, Graph graph)
        {
            var diagram = diagramView.Diagram;
            if (diagram.Nodes.Count == 0)
            {
                foreach (var node in graph.Nodes)
                    diagram.Nodes.Add(new IconNode(diagram) { Label = node.Name, BackColor = StateColours[node.State] });
                foreach (IconNode node in diagram.Nodes)
                    foreach (var child in graph.Nodes.Single(t => t.Name == node.Label).Children)
                        diagram.Links.Add(new Relation(
                            diagram,
                            node,
                            diagram.Nodes.Cast<IconNode>().Single(t => t.Label == child.Name),
                            child.CurrentMessage));
                DoLayout(diagramView);
            }
            else if (diagram.Nodes.Count == graph.Nodes.Count)
                foreach (var node in graph.Nodes)
                {
                    var n = diagram.Nodes.Cast<IconNode>().Single(t => t.Label == node.Name);
                    n.BackColor = StateColours[node.State];
                    n.Comment = node.Tag;
                    n.ToolTip = node.ToolTipMessage;
                    foreach (var link in n.OutgoingLinks)
                    {
                        ((Relation)link).LinkTitle = node.CurrentMessage;
                    }
                }
            else throw new ArgumentOutOfRangeException();
        }

        private static void DoLayout(DiagramView diagramView)
        {
            var frm = new Form { TopMost = true, StartPosition = FormStartPosition.CenterScreen, FormBorderStyle = FormBorderStyle.None, Opacity = 0.8, BackgroundImage = Resources.Wait, Size = Resources.Wait.Size };
            frm.Show();
            var springLayout = new SpringLayout { NodeDistance = 145, IterationCount = 5000 };
            diagramView.Diagram.RoutingOptions.CrossingCost = 50;
            springLayout.Arrange(diagramView.Diagram);
            diagramView.ZoomToFit();
            frm.Close();
        }

        private static bool NextStepPossible(IStepController wc, DiagramView diagramView)
        {
            if (wc.IsEnd()) return false;
            var graph = wc.NextStep();
            BuildGraph(diagramView, graph);
            return true;
        }

        private void FormMainMouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta > 0)
                diagramView1.ZoomIn();
            else
                diagramView1.ZoomOut();
        }

        private void LeLanStep()
        {
            if (_LeLan == null || (!NextStepPossible(_LeLan, diagramView1)
                && MessageBox.Show(StrRepeat, "", MessageBoxButtons.YesNoCancel) == DialogResult.Yes))
            {
                _LeLan = new ElectionRingLeLanController(par1, par2, rtbLog);
                diagram1.ClearAll();
                rtbLog.Clear();
                BuildGraph(diagramView1, _LeLan.GetCurrentState());
            }
        }

        private void ChenRobertsStep()
        {
            if (_ChenRoberts == null || (!NextStepPossible(_ChenRoberts, diagramView1)
                && MessageBox.Show(StrRepeat, "", MessageBoxButtons.YesNoCancel) == DialogResult.Yes))
            {
                _ChenRoberts = new ElectionRingChenRoberts(par1, par2, rtbLog);
                diagram1.ClearAll();
                rtbLog.Clear();
                BuildGraph(diagramView1, _ChenRoberts.GetCurrentState());
            }
        }

        private void PetersonStep()
        {
            if (_Peterson == null || (!NextStepPossible(_Peterson, diagramView1)
                && MessageBox.Show(StrRepeat, "", MessageBoxButtons.YesNoCancel) == DialogResult.Yes))
            {
                _Peterson = new ElectionRingPeterson(par1, par2, rtbLog);
                diagram1.ClearAll();
                rtbLog.Clear();
                BuildGraph(diagramView1, _Peterson.GetCurrentState());
            }
        }

        private void PhaseStep()
        {
            if (_Phase == null || (!NextStepPossible(_Phase, diagramView1)
                && MessageBox.Show(StrRepeat, "", MessageBoxButtons.YesNoCancel) == DialogResult.Yes))
            {
                _Phase = new ElectionRingPhase(par1, par2, par3, rtbLog);
                diagram1.ClearAll();
                rtbLog.Clear();
                BuildGraph(diagramView1, _Phase.GetCurrentState());
            }
        }

        private void TreeStep()
        {
            if (_Tree == null || (!NextStepPossible(_Tree, diagramView1)
                && MessageBox.Show(StrRepeat, "", MessageBoxButtons.YesNoCancel) == DialogResult.Yes))
            {
                _Tree = new ElectionRingTree(par1, par2, par3, 2, rtbLog);
                diagram1.ClearAll();
                rtbLog.Clear();
                BuildGraph(diagramView1, _Tree.GetCurrentState());
            }
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            cmbAlgorithms.SelectedIndex = 0;
        }

        private void BtnNextStep_Click(object sender, EventArgs e)
        {
            cmbAlgorithms.Enabled = false;

            if (!int.TryParse(tbParameter1.Text, out par1))
                throw new Exception("Некорректное значение параметра 1");
            if (!int.TryParse(tbParameter2.Text, out par2))
                throw new Exception("Некорректное значение параметра 2");
            if (gbParameter3.Enabled && !int.TryParse(tbParameter3.Text, out par3))
                throw new Exception("Некорректное значение параметра 3");

            switch (cmbAlgorithms.SelectedIndex)
            {
                case (0): { LeLanStep(); break; }
                case (1): { ChenRobertsStep(); break; }
                case (2): { PetersonStep(); break; }
                case (3): { TreeStep(); break; }
                case (4): { PhaseStep(); break; }
            }

            rtbLog.Text += "\n";
        }

        private void BtnStop_Click(object sender, EventArgs e)
        {
            cmbAlgorithms.Enabled = true;
            //пересоздание текущего контроллера
            switch (cmbAlgorithms.SelectedIndex)
            {
                case (0): { _LeLan = new ElectionRingLeLanController(par1, par2, rtbLog); break; }
                case (1): { _ChenRoberts = new ElectionRingChenRoberts(par1, par2, rtbLog); break; }
                case (2): { _Peterson = new ElectionRingPeterson(par1, par2, rtbLog); break; }
                case (3): { _Tree = new ElectionRingTree(par1, par2, par3, 2, rtbLog); break; }
                case (4): { _Phase = new ElectionRingPhase(par1, par2, par3, rtbLog); break; }
            }
            diagram1.ClearAll();
        }

        private void btnDescription_Click(object sender, EventArgs e)
        {
            System.IO.StreamReader file =
                new System.IO.StreamReader("Description.txt");

            string description = file.ReadToEnd().Split(new string[] { "Separator" }, StringSplitOptions.None)[cmbAlgorithms.SelectedIndex];

            MessageBox.Show(description);

            file.Close();
        }

        private void cmbAlgorithms_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (cmbAlgorithms.SelectedIndex)
            {
                case (3):
                    {
                        gbParameter1.Text = "Глубина дерева";
                        gbParameter2.Text = "Мин. число потомков";
                        gbParameter3.Text = "Макс. число потомков";
                        gbParameter3.Enabled = true;
                        gbParameter3.Visible = true;
                        break;
                    }
                case (4):
                    {
                        gbParameter1.Text = "Общее число вершин";
                        gbParameter2.Text = "Число ребер";
                        gbParameter3.Text = "Число инициаторов";
                        gbParameter3.Enabled = true;
                        gbParameter3.Visible = true;
                        break;
                    }
                default:
                    {
                        gbParameter1.Text = "Общее число вершин";
                        gbParameter2.Text = "Число инициаторов";
                        gbParameter3.Enabled = false;
                        gbParameter3.Visible = false;
                        break;
                    }
            }
        }

    }
}
